#include "tcpconnection.h"
#include "channel.h"
#include "eventloop.h"

#include <unistd.h>
#include <sys/socket.h>
#include <cstring>
#include <iostream>

TcpConnection::TcpConnection(EventLoop* loop, int sockfd)
    : loop_(loop), sockfd_(sockfd),closed_(false),
      channel_(std::make_shared<Channel>(loop, sockfd)) {

    channel_->setReadCallback([this]() { handleRead(); });
    channel_->setWriteCallback([this]() { handleWrite(); });
    channel_->setCloseCallback([this]() { handleClose(); });

    channel_->enableReading();

    if (connectionCallback_) {
        connectionCallback_(shared_from_this());
    }
}

TcpConnection::TcpConnection(EventLoop* loop, int sockfd, const std::string& peerAddr)
    : loop_(loop), sockfd_(sockfd), closed_(false), peerAddr_(peerAddr),
      channel_(std::make_shared<Channel>(loop, sockfd)) {

    channel_->setReadCallback([this]() { handleRead(); });
    channel_->setWriteCallback([this]() { handleWrite(); });

    channel_->enableReading();

    if (connectionCallback_) {
        connectionCallback_(shared_from_this());
    }
}

TcpConnection::~TcpConnection() {
    if (!closed_) {
        ::close(sockfd_);
        closed_ = true;
    }
}

void TcpConnection::handleRead() {
    if (closed_) return;
    char buf[4096];
    ssize_t n = ::read(sockfd_, buf, sizeof(buf));

    if (n > 0) {
        readBuffer_.append(buf, n);
        if (messageCallback_) {
            messageCallback_(shared_from_this(), readBuffer_);
            readBuffer_.clear();
        }
    } else if (n == 0) {
        shutdown();
    } else {
        perror("read");
        shutdown();
    }
}

void TcpConnection::handleWrite() {
    if (closed_) return;
    ssize_t n = ::write(sockfd_, writeBuffer_.data(), writeBuffer_.size());
    if (n > 0) {
        writeBuffer_ = writeBuffer_.substr(n);
        if (writeBuffer_.empty()) {
            channel_->disableWrite();
        }
    } else {
        perror("write");
        shutdown();
    }
}

void TcpConnection::handleClose() {
        shutdown();
        if (closeCallback_) {
            closeCallback_(shared_from_this());
        }
    }

void TcpConnection::send(const std::string& data) {
    if (closed_) return;
    writeBuffer_ += data;
    channel_->enableWrite();
}

void TcpConnection::shutdown() {
    if (closed_) return;
    closed_ = true;

    channel_->disableAll();
    channel_->remove();

    ::close(sockfd_);
    
    if (closeCallback_) {
        closeCallback_(shared_from_this());
    }
}
